package pl.edu.mimuw.mas.agent.behaviour.hunting;

import pl.edu.mimuw.mas.agent.HuntingAgent;
import pl.edu.mimuw.mas.agent.behaviour.MutableTimedBehaviour;
import pl.edu.mimuw.mas.util.Move;
import pl.edu.mimuw.mas.util.Position;
import pl.edu.mimuw.mas.util.PositionHelper;
import pl.edu.mimuw.mas.util.Time;

public class MoveBehaviour extends MutableTimedBehaviour {

	private static final long serialVersionUID = -8257303696547411376L;

	public MoveBehaviour(HuntingAgent a) {
		super(a, 1);
	}

	@Override
	protected void onTick() {
		HuntingAgent a = (HuntingAgent) myAgent;
		// szukam najlepszego ruchu
		Move move = getBestMove();
		// ruszam sie
		PositionHelper.move((HuntingAgent) myAgent, move);
		// ustawiam prędkość (czas kroku)
		int maxx = a.getChart().getColumnsCount() - 1;
		int maxy = a.getChart().getRowsCount() - 1;
		float maxDistance = PositionHelper.getDistance(new Position(0, 0),
				new Position(maxx, maxy));
		float deerDistance;
		if (a.getDeerPosition() != null) {
			 deerDistance = PositionHelper.getDistance(a.getPosition(), a.getDeerPosition());
		} else {
			deerDistance = maxDistance;
		}
		int speed = Time.HUNTING_STEP_MIN
				+ (int) ((float) (Time.HUNTING_STEP_MAX - Time.HUNTING_STEP_MIN)
						* Math.sqrt(deerDistance / maxDistance));
		setPeriod(speed);
	}

	private Move getBestMove() {
		HuntingAgent a = (HuntingAgent) myAgent;
		Position p = a.getPosition(); // position
		Position dp = a.getDeerPosition(); // deerposition
		long lu = a.getLastDeerPositionUpdate();
		
		// jesli pozycja zbyt stara to ruszam sie losowo
		if (System.currentTimeMillis() - lu > Time.HUNTING_DEER_POSITION_TRUSTED) {
			return PositionHelper.getRandomMove();
		}

		// licze wektor ruchu
		int max = Math.max(Math.abs(dp.x - p.x), Math.abs(dp.y - p.y));
		int vx = (int) Math.round((double) (dp.x - p.x) / max);
		int vy = (int) Math.round((double) (dp.y - p.y) / max);

		// wektory normalne
		int normalvx1 = -vy;
		int normalvy1 = vx;
		int normalvx2 = vy;
		int normalvy2 = -vx;

		// odleglosci do agentow
		float adist = PositionHelper.getAverageDistance(a, new Position(p.x
				+ vx, p.y + vy));
		float adist1 = PositionHelper.getAverageDistance(a, new Position(p.x
				+ vx + normalvx1, p.y + vy + normalvy1));
		float adist2 = PositionHelper.getAverageDistance(a, new Position(p.x
				+ vx + normalvx2, p.y + vy + normalvy2));
		float maxdist = max(adist, adist1, adist2);

		if (maxdist == adist) {
			return new Move(vx, vy);
		} else if (maxdist == adist1) {
			return new Move(vx + normalvx1, vy + normalvy1);
		} else {
			return new Move(vx + normalvx2, vy + normalvy2);
		}

	}

	private static float max(float a, float b, float c) {
		return Math.max(a, Math.max(b, c));
	}

}
